home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / MORSE_CD / MORSE_CD.C next >
Text File  |  1989-11-11  |  10KB  |  419 lines

  1. /*
  2.     Example of a cdev/INIT program written in THINK C 3.02.
  3.  
  4.     The 'INIT' will play some morse code at startup, using parameters in
  5.     the 'PARM' resource. The 'cdev' allows to modify these parameters
  6.     through the control panel DA.
  7.     
  8.     There are two other projects that build code resources, and these code
  9.     resources must be included in 'Morse CDEV ╣.rsrc' with ResEdit:
  10.  
  11.         Morse Play ╣ --> 'PLAY' resource, contains the function MorsePlay()
  12.         Morse INIT ╣ --> 'INIT'    resource, called at system startup
  13.  
  14.     Use 'Set Project Type...', then select 'Code Resource', set type 'cdev',
  15.     ID -4064, purgeable. The file type should be set to type 'cdev' with
  16.     creator 'LXYZ'.
  17. */
  18.  
  19. #define CREATOR    'LXYZ'
  20.  
  21. #define ICON    -4064    /* Resource id of 'ICN#' */
  22. #define PARM    -4048    /* Resource id of 'PARM' */
  23. #define PLAY    -4048    /* Resource id of 'PLAY' */
  24. #define CURS    -4064    /* Resource id of 'CURS' */
  25.  
  26.                     /* 'DITL' items */
  27. #define    iEnable        1    /* Enable INIT (radio button) */
  28. #define    iDisable    2    /* Disable INIT (radio button) */
  29. #define    iText        3    /* Text to morse (editText) */
  30. #define    iIcon        4    /* iconItem */
  31. #define iFrequency    5    /* Frequency (editText) */
  32. #define iVolume        6    /* Volume (editText) */
  33. #define iSpeed        7    /* Speed (editText) */
  34. #define iVersion    11    /* Version (staticText) */
  35.  
  36. #define MorsePlay(a,b,c,d) (*mp)(a,b,c,d)
  37.  
  38. typedef void (*PF)();    /* Pointer to function returning void */
  39.  
  40. typedef struct Parameter {    /* Structure of 'PARM' resource */
  41.     Boolean        enable;        /* Enable INIT */
  42.     short        parm[3];    /* Frequency, volume and speed */
  43.     char        text[256];    /* Pascal string, text to morse */
  44. } Parameter;
  45.  
  46. typedef struct Storage {    /* Storage needed between calls to 'cdev' */
  47.     DialogPtr    dlgPtr;        /* Pointer to the control pannel dialog */
  48.     short        dlgItems;    /* Dialog items used by control pannel */
  49.     Cursor        curs;        /* Our cursor */
  50.     Boolean        dirty;        /* Set if var modified */
  51.     Boolean        toggle;
  52.     Parameter    var;
  53. } Storage, *StoragePtr, **StorageHdl;
  54.  
  55. char ERNY[] = "\p DE LX1YZ \0";
  56. #define FREQ    800
  57. #define VOLUME    64
  58. #define SPEED    3
  59.  
  60. /* ----- Function prototypes ------------------------------------------- */
  61.  
  62. void Invalidate (StoragePtr, short);
  63. Handle GetCtlHdl (StoragePtr, short);
  64. Boolean NewValues (StoragePtr);
  65. void Hit (StoragePtr, short);
  66. void Key (EventRecord *, DialogPtr, short);
  67. long Init (DialogPtr, short);
  68. void Hide (DialogPtr, short);
  69. void Bye (StoragePtr);
  70. pascal long main (short,short,short,short,EventRecord *,long,DialogPtr);
  71.  
  72. /* ----- Get handle for given dialog item ------------------------------ */
  73.  
  74. Handle GetCtlHdl (p, item)
  75. register StoragePtr p;
  76. register short item;
  77. {
  78.     Handle Hdl;
  79.     Rect r;
  80.     short type;
  81.  
  82.     GetDItem(p->dlgPtr, item + p->dlgItems, &type, &Hdl, &r);
  83.     return Hdl;
  84. }
  85.  
  86. /* ----- Erase and invalidate dialog item ------------------------------ */
  87.  
  88. void Invalidate (p, item)
  89. register StoragePtr p;
  90. register short item;
  91. {
  92.     short type;
  93.     Handle hdl;
  94.     Rect r;
  95.  
  96.     GetDItem(p->dlgPtr, item + p->dlgItems, &type, &hdl, &r);
  97.     EraseRect(&r);
  98.     InvalRect(&r);
  99. }
  100.  
  101. /* ----- Read new values from TextEdit fields -------------------------- */
  102.  
  103. Boolean NewValues (p)
  104. register StoragePtr p;
  105. {
  106.     register char s[256];
  107.     register Handle ctrl;
  108.     register short i;
  109.     register Boolean err;
  110.     long v;
  111.  
  112.     ctrl = GetCtlHdl(p, iText);
  113.     GetIText(ctrl, s);
  114.     if (!EqualString(s, p->var.text, TRUE, TRUE)) {
  115.         p->dirty = TRUE;
  116.         BlockMove(s, p->var.text, *s + 1);
  117.     }
  118.     for (i = iFrequency; i <= iSpeed; i++) {
  119.         ctrl = GetCtlHdl(p, i);
  120.         GetIText(ctrl, s);
  121.         StringToNum(s , &v);
  122.         switch (i) {
  123.             case iFrequency:
  124.                 err = v < 200 || v > 2000;
  125.                 break;
  126.             case iVolume:
  127.                 err = v > 255;
  128.                 break;
  129.             case iSpeed:
  130.                 err = v < 1 || v > 10;
  131.                 break;
  132.         }
  133.         if (err) {
  134.             SysBeep(1);
  135.             SelIText(p->dlgPtr, p->dlgItems + i, 0, 32767);
  136.             return TRUE;    /* Error */
  137.         }
  138.         if (p->var.parm[i - iFrequency] != v) {
  139.             p->dirty = TRUE;
  140.             p->var.parm[i - iFrequency] = v;
  141.         }
  142.     }
  143.     return FALSE;            /* No error */
  144. }
  145.  
  146. /* ----- Handle a hit in one of our DITL items ------------------------- */
  147.  
  148. void Hit (p, item)
  149. register StoragePtr p;
  150. register short item;
  151. {
  152.     register PF mp, *mh;
  153.     Handle ctrl, text;
  154.  
  155.     switch (item) {
  156.         case iEnable:
  157.             p->dirty = TRUE;
  158.             p->var.enable = TRUE;
  159.             SetCtlValue(GetCtlHdl(p, iEnable), TRUE);
  160.             SetCtlValue(GetCtlHdl(p, iDisable), FALSE);
  161.             break;
  162.         case iDisable:
  163.             p->dirty = TRUE;
  164.             p->var.enable = FALSE;
  165.             SetCtlValue(GetCtlHdl(p, iEnable), FALSE);
  166.             SetCtlValue(GetCtlHdl(p, iDisable), TRUE);
  167.             break;
  168.         case iIcon:
  169.             if (NewValues(p))
  170.                 break;
  171.             Invalidate(p, item);
  172.             if (mh = (PF *)GetResource('PLAY', PLAY)) {
  173.                 HLock(mh);
  174.                 mp = *mh;
  175.                 PtoCstr(p->var.text);
  176.                 MorsePlay(p->var.text, p->var.parm[0],
  177.                     p->var.parm[1], p->var.parm[2]);
  178.                 CtoPstr(p->var.text);
  179.                 ReleaseResource(mh);
  180.             }
  181.             break;
  182.         case iVersion:
  183.             Invalidate(p, item);
  184.             if (mh = (PF *)GetResource('PLAY', PLAY)) {
  185.                 HLock(mh);
  186.                 mp = *mh;
  187.                 MorsePlay(ERNY + 1, FREQ, VOLUME, SPEED);
  188.                 ReleaseResource(mh);
  189.             }
  190.             ctrl = GetCtlHdl(p, iVersion);
  191.             p->toggle = !p->toggle;
  192.             if (p->toggle)
  193.                 SetIText(ctrl, ERNY);
  194.             else 
  195.                 if (text = GetResource(CREATOR, 0)) {
  196.                     HLock(text);
  197.                     SetIText(ctrl, *text);
  198.                     ReleaseResource(text);
  199.                 }
  200.             break;
  201.     }
  202. }
  203.  
  204. /* ----- Handle keystrokes --------------------------------------------- */
  205.  
  206. void Key (event, dialog, num)
  207. register EventRecord *event;
  208. register DialogPtr dialog;
  209. register short num;
  210. {
  211.     register char key;
  212.     
  213.     key = event->message & charCodeMask;
  214.     if (event->modifiers & cmdKey) {
  215.         event->what = nullEvent;
  216.         switch (key) {
  217.             case 'k':    /* Cut */
  218.             case 'K':
  219.                 DlgCut(dialog);
  220.                 break;
  221.             case 'c':    /* Copy */
  222.             case 'C':
  223.                 DlgCopy(dialog);
  224.                 break;
  225.             case 'v':    /* Paste */
  226.             case 'V':
  227.                 DlgPaste(dialog);
  228.                 break;
  229.             default:
  230.                 SysBeep(1);
  231.         }
  232.     } else
  233.         if (key != '\t' && key != '\b')
  234.             switch (((DialogPeek)dialog)->editField + 1 - num) {
  235.                 case iText:
  236.                     if (key >= 'a' && key <= 'z')
  237.                         key -= 'a' - 'A';
  238.                     if (key < ' ' || key > '_') {
  239.                         SysBeep(1);
  240.                         event->what = nullEvent;
  241.                     }
  242.                     break;
  243.                 case iFrequency:
  244.                 case iVolume:
  245.                 case iSpeed:
  246.                     if (key < '0' || key > '9') {
  247.                         SysBeep(1);
  248.                         event->what = nullEvent;
  249.                     }
  250.                     break;
  251.             }
  252. }
  253.  
  254. /* ----- Hide EditText items ------------------------------------------- */
  255.  
  256. /* See TN #251 why the EditText items should be hidden */
  257.  
  258. void Hide (dialog, num)
  259. register DialogPtr dialog;
  260. register short num;
  261. {
  262.     HideDItem(dialog, num + iText);
  263.     HideDItem(dialog, num + iFrequency);
  264.     HideDItem(dialog, num + iVolume);
  265.     HideDItem(dialog, num + iSpeed);
  266. }
  267.  
  268. /* ----- Initialize the cdev ------------------------------------------- */
  269.  
  270. long Init (dialog, num)
  271. DialogPtr dialog;
  272. short num;
  273. {
  274.     StorageHdl h;
  275.     register StoragePtr p;
  276.     register Handle text;
  277.     register Handle ctrl;
  278.     register short i;
  279.     char s[256];
  280.     CursHandle ch;
  281.  
  282.     if (h = (StorageHdl)NewHandle(sizeof(Storage))) {
  283.         HLock(h);
  284.         p = *h;
  285.         p->dlgPtr = dialog;
  286.         p->dlgItems = num;
  287.         if (ch = GetCursor(CURS))
  288.             p->curs = **ch;
  289.         p->dirty = FALSE;
  290.         p->toggle = FALSE;
  291.         if ((text = GetResource('PARM', PARM)) && !ResError()) {
  292.             BlockMove(*text, &p->var, sizeof(Parameter));
  293.             ReleaseResource(text);
  294.         } else {
  295.             p->var.enable = FALSE;
  296.             p->var.parm[0] = FREQ;
  297.             p->var.parm[1] = VOLUME;
  298.             p->var.parm[2] = SPEED;
  299.             BlockMove(ERNY, p->var.text, *ERNY + 1);
  300.         }
  301.         SetCtlValue(GetCtlHdl(p, iEnable), p->var.enable);
  302.         SetCtlValue(GetCtlHdl(p, iDisable), !p->var.enable);
  303.         for (i = iFrequency; i <= iSpeed; i++) {
  304.             NumToString(p->var.parm[i - iFrequency], s);
  305.             ctrl = GetCtlHdl(p, i);
  306.             SetIText(ctrl, s);
  307.         }
  308.         ctrl = GetCtlHdl(p, iText);
  309.         SetIText(ctrl, p->var.text);
  310.         SelIText(dialog, num + iText, 0, 32767);
  311.         if (text = GetResource(CREATOR, 0)) {
  312.             HLock(text);
  313.             ctrl = GetCtlHdl(p, iVersion);
  314.             SetIText(ctrl, *text);
  315.             ReleaseResource(text);
  316.         }
  317.         HUnlock(h);
  318.     } else
  319.         Hide(dialog, num);
  320.     return (long)h;
  321. }
  322.  
  323. /* ----- Bye bye ------------------------------------------------------- */
  324.  
  325. void Bye (p)
  326. register StoragePtr p;
  327. {
  328.     register Handle text;
  329.     register char empty[1];
  330.  
  331.     if (p->dirty) {
  332.         empty[0] = 0;
  333.         if (text = GetResource('PARM', PARM)) {
  334.             RmveResource(text);
  335.             DisposHandle(text);
  336.         }
  337.         if (text = NewHandle((long)sizeof(Parameter))) {
  338.             BlockMove(&p->var, *text, sizeof(Parameter));
  339.             AddResource(text, 'PARM', PARM, empty);
  340.             if (!ResError()) {
  341.                 WriteResource(text);
  342.                 ReleaseResource(text);
  343.             }
  344.         }
  345.     }
  346. }
  347.  
  348. /* ----- The 'cdev' dispatch function ---------------------------------- */
  349.  
  350. pascal long main (message, item, num, id, event, value, dialog)
  351. short message;
  352. register short item;
  353. register short num;
  354. short id;
  355. EventRecord *event;
  356. register long value;
  357. DialogPtr dialog;
  358. {
  359.     asm {
  360.         MOVE A4,-(SP)    /* Save A4 */
  361.         MOVE.L A0,A4    /* A4 used for global and static data */
  362.     }
  363.     if (message != initDev && message != macDev && 
  364.             (!value || value == cdevUnset))
  365.         value = 0;
  366.     else
  367.         switch (message) {
  368.             case initDev:        /* Initialization */
  369.                 TEFromScrap();
  370.                 value = Init(dialog, num);
  371.                 break;
  372.             case hitDev:        /* User clicked dialog item */
  373.                 HLock(value);
  374.                 Hit(*(StorageHdl)value, item - num);
  375.                 HUnlock(value);
  376.                 break;
  377.             case closeDev:        /* Selected another cdev or CP closed */
  378.                 ZeroScrap();
  379.                 TEToScrap();
  380.                 if (value) {
  381.                     HLock(value);
  382.                     Bye(*(StorageHdl)value);
  383.                     DisposHandle(value);
  384.                     value = 0;
  385.                 }
  386.                 break;
  387.             case activDev:        /* Activate event */
  388.                 TEFromScrap();
  389.                 break;
  390.             case deactivDev:    /* Deactivate event */
  391.                 ZeroScrap();
  392.                 TEToScrap();
  393.                 break;
  394.             case keyEvtDev:        /* Key-down or auto-key event */
  395.                 Key(event, dialog, num);
  396.                 break;
  397.             case cutDev:
  398.                 DlgCut(dialog);
  399.                 break;
  400.             case copyDev:
  401.                 DlgCopy(dialog);
  402.                 break;
  403.             case pasteDev:
  404.                 DlgPaste(dialog);
  405.                 break;
  406.             case clearDev:
  407.                 DlgDelete(dialog);
  408.                 break;
  409.             case 14 /* cursorDev (see TN #215) */:
  410.                 if (value)
  411.                     SetCursor(&(**(StorageHdl)value).curs);
  412.                 break;
  413.         }
  414.     asm {
  415.         MOVE (SP)+,A4    /* Restore A4 */
  416.     }
  417.     return value;
  418. }
  419.